#pragma once

#ifdef _MSC_VER
	#define WIN32_LEAN_AND_MEAN
	#include <Windows.h>
#endif
#include <boost/asio.hpp>
#include <memory>

struct ASIOErrrCode
{
	boost::system::error_code ec;
	std::size_t bytes;

	ASIOErrrCode() 
		: bytes(0)
	{		
	}
};

struct ASIOConnection : public std::enable_shared_from_this<ASIOConnection>
{
	ASIOConnection(boost::asio::ip::tcp::socket sock)
		: m_socket(std::move(sock))
	{
		m_socket.non_blocking(true);
	}

	inline bool is_open() const
	{
		return m_socket.is_open();
	}

	inline void close()
	{
		if (is_open())
			m_socket.close();
	}
	std::size_t read(void* buffer, std::size_t length, boost::system::error_code* pec = nullptr);
	std::size_t read_some(void* buffer, std::size_t length, boost::system::error_code* pec = nullptr);
	std::size_t write(const void* buffer, std::size_t length, boost::system::error_code* pec = nullptr);
	std::size_t write_some(const void* buffer, std::size_t length, boost::system::error_code* pec = nullptr);
private:
	ASIOErrrCode m_read_ec;
	ASIOErrrCode m_write_ec;
	boost::asio::ip::tcp::socket m_socket;
};

struct ASIOConnector : public std::enable_shared_from_this<ASIOConnector>
{
	ASIOConnector(boost::asio::io_service& ioservice)
		: m_socket(ioservice)
	{
	}

	boost::system::error_code connect(const char* addr, const char* port);
	boost::system::error_code connect(const boost::asio::ip::tcp::endpoint& endpoint); 
	
	boost::asio::ip::tcp::socket& socket() { return m_socket; }
	std::shared_ptr<ASIOConnection> make_connection();
private:
	boost::asio::ip::tcp::socket m_socket;
	ASIOErrrCode m_connect_ec;
};

struct ASIOAcceptor : public std::enable_shared_from_this<ASIOAcceptor>
{
	ASIOAcceptor(boost::asio::io_service& ioservice, const boost::asio::ip::tcp::endpoint& endpoint)
		: m_acceptor(ioservice, endpoint)
		, m_socket(ioservice)
	{
	}
	boost::system::error_code accept();
	boost::asio::ip::tcp::acceptor& asio_acceptor() { return m_acceptor; }
	boost::asio::ip::tcp::socket& socket() { return m_socket; }
	std::shared_ptr<ASIOConnection> make_accepted_connection();
private:
	boost::asio::ip::tcp::acceptor m_acceptor;
	boost::asio::ip::tcp::socket m_socket;
	ASIOErrrCode m_accept_ec;
};

struct ASIOUtils
{
	static void sleep(boost::asio::io_service& ioservice,unsigned int millsecs);
};